import os
import subprocess
from datetime import datetime, timedelta
from PyQt5 import QtCore, QtGui, QtWidgets

# Helper function to retrieve all files ending in "o"
def get_o_files(directory):
    return [f for f in os.listdir(directory) if f.endswith('o')]

# Helper function to retrieve all files ending in "n" or "g" "l" or "c"
def get_nav_files(directory):
    return [f for f in os.listdir(directory) if f.endswith('n') or f.endswith('g') or f.endswith('c') or f.endswith('l')]

# Command to split file
def run_gfzrnx(input_file, start_time_str, duration, directory):
    input_path = os.path.join(directory, input_file)
    output_file = "split_" + input_file
    output_path = os.path.join(directory, output_file)
    command = f'gfzrnx -finp "{input_path}" -epo_beg {start_time_str} -d {duration} -kv > "{output_path}"'
    return command

# Command to convert file version
def run_version_conversion(input_file, version, directory):
    input_path = os.path.join(directory, input_file)
    output_file = "convert_" + input_file
    output_path = os.path.join(directory, output_file)
    command = f'gfzrnx -finp "{input_path}" -vo {version} > "{output_path}"'
    return command

# Command to merge files
def run_file_merge(files, directory):
    input_files = ' '.join([f'"{os.path.join(directory, f)}"' for f in files])
    output_file = "merge_" + files[0]
    output_path = os.path.join(directory, output_file)
    command = f'gfzrnx -finp {input_files} -kv > "{output_path}"'
    return command

# Command to merge ephemeris files
def run_ephemeris_merge(files, directory):
    input_files = ' '.join([f'"{os.path.join(directory, f)}"' for f in files])
    output_file = "merged_ephemeris.nav"
    output_path = os.path.join(directory, output_file)
    command = f'gfzrnx -finp {input_files} -kv > "{output_path}"'
    return command

# Command to exclude satellite by PRNs
def run_satellite_edit(input_file, prns, directory):
    input_path = os.path.join(directory, input_file)
    output_file = "edit_" + input_file
    output_path = os.path.join(directory, output_file)
    command = f'gfzrnx -finp "{input_path}" -no_prn {prns} -kv > "{output_path}"'
    return command

# Command to resample file
def run_file_smp(input_file, smp_str, directory):
    input_path = os.path.join(directory, input_file)
    output_file = "smp_" + smp_str + "_" + input_file
    output_path = os.path.join(directory, output_file)
    command = f'gfzrnx -finp "{input_path}" -smp {smp_str} -kv > "{output_path}"'
    return command

# Convert GPS time to UTC
def gps_to_utc(year, week, seconds):
    gps_epoch = datetime(1980, 1, 6)
    total_seconds = week * 7 * 24 * 3600 + seconds
    utc_time = gps_epoch + timedelta(seconds=total_seconds)
    return utc_time

# Custom dialog to input time in components
class TimeInputDialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.initUI()

    def initUI(self):
        layout = QtWidgets.QFormLayout()

        # Adding inputs for each component of time
        self.year_input = QtWidgets.QSpinBox()
        self.year_input.setRange(1980, 2100)
        self.year_input.setValue(datetime.now().year)
        layout.addRow("年:", self.year_input)

        self.month_input = QtWidgets.QSpinBox()
        self.month_input.setRange(1, 12)
        self.month_input.setValue(datetime.now().month)
        layout.addRow("月:", self.month_input)

        self.day_input = QtWidgets.QSpinBox()
        self.day_input.setRange(1, 31)
        self.day_input.setValue(datetime.now().day)
        layout.addRow("日:", self.day_input)

        self.hour_input = QtWidgets.QSpinBox()
        self.hour_input.setRange(0, 23)
        layout.addRow("小时:", self.hour_input)

        self.minute_input = QtWidgets.QSpinBox()
        self.minute_input.setRange(0, 59)
        layout.addRow("分钟:", self.minute_input)

        self.second_input = QtWidgets.QSpinBox()
        self.second_input.setRange(0, 59)
        layout.addRow("秒:", self.second_input)

        # Adding dialog buttons
        button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        layout.addRow(button_box)

        self.setLayout(layout)
        self.setWindowTitle("输入起始时间")

    def get_time(self):
        year = self.year_input.value()
        month = self.month_input.value()
        day = self.day_input.value()
        hour = self.hour_input.value()
        minute = self.minute_input.value()
        second = self.second_input.value()
        start_time = datetime(year, month, day, hour, minute, second)
        return start_time.strftime('%Y-%m-%d_%H:%M:%S')

# Main GFZRNX Tool GUI
class GFZRNXTool(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.find_gfzrnx_exe()  # Automatically find gfzrnx.exe on startup

    def initUI(self):
        layout = QtWidgets.QVBoxLayout()

        self.label = QtWidgets.QLabel("请选择功能:")
        layout.addWidget(self.label)

        # Adding feature buttons
        self.button1 = QtWidgets.QPushButton("文件切割")
        self.button1.clicked.connect(self.file_split)
        layout.addWidget(self.button1)

        self.button2 = QtWidgets.QPushButton("文件版本转换")
        self.button2.clicked.connect(self.file_version_conversion)
        layout.addWidget(self.button2)

        self.button3 = QtWidgets.QPushButton("文件合并")
        self.button3.clicked.connect(self.file_merge)
        layout.addWidget(self.button3)

        self.button4 = QtWidgets.QPushButton("删除卫星")
        self.button4.clicked.connect(self.satellite_edit)
        layout.addWidget(self.button4)

        self.button5 = QtWidgets.QPushButton("文件重采样")
        self.button5.clicked.connect(self.file_smp)
        layout.addWidget(self.button5)
        
        
        self.button6 = QtWidgets.QPushButton("星历合并")
        self.button6.clicked.connect(self.ephemeris_merge)
        layout.addWidget(self.button6)

        # Command output display
        self.command_label = QtWidgets.QLabel("生成的命令:")
        layout.addWidget(self.command_label)

        self.command_text = QtWidgets.QTextEdit()
        self.command_text.setReadOnly(True)
        layout.addWidget(self.command_text)

        self.setLayout(layout)
        self.setWindowTitle('GFZRNX 工具')
        self.setGeometry(800, 800, 800, 500)

    # Automatically search for gfzrnx.exe
    def find_gfzrnx_exe(self):
        current_dir = os.path.dirname(os.path.abspath(__file__))
        gfzrnx_path = None

        # Check current and parent directories for gfzrnx.exe
        if 'gfzrnx.exe' in os.listdir(current_dir):
            gfzrnx_path = os.path.join(current_dir, 'gfzrnx.exe')
        else:
            parent_dir = os.path.abspath(os.path.join(current_dir, '..'))
            if 'gfzrnx.exe' in os.listdir(parent_dir):
                gfzrnx_path = os.path.join(parent_dir, 'gfzrnx.exe')

        # If not found, prompt user to select gfzrnx.exe
        if gfzrnx_path:
            self.gfzrnx_exe_path = gfzrnx_path
            self.gfzrnx_directory = os.path.dirname(gfzrnx_path)
            QtWidgets.QMessageBox.information(self, "信息", f"找到 gfzrnx.exe: {self.gfzrnx_exe_path}")
        else:
            QtWidgets.QMessageBox.critical(self, "错误", "无法找到 gfzrnx.exe，请手动选择路径")
            self.select_gfzrnx_exe()

    # Manual selection of gfzrnx.exe if not automatically found
    def select_gfzrnx_exe(self):
        file, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择 gfzrnx.exe 文件", "", "Executable Files (gfzrnx.exe)")
        if file:
            self.gfzrnx_exe_path = file
            self.gfzrnx_directory = os.path.dirname(file)
            QtWidgets.QMessageBox.information(self, "信息", f"找到 gfzrnx.exe: {self.gfzrnx_exe_path}")
        else:
            self.gfzrnx_exe_path = None
            self.gfzrnx_directory = None

    # Select observation file
    def select_obs_file(self):
        options = QtWidgets.QFileDialog.Options()
        file, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择观测文件", "", "All Files (*);;Observation Files (*.o)", options=options)
        if file:
            self.obs_file = file
            self.obs_directory = os.path.dirname(file)
        else:
            self.obs_file = None

    # Select observation directory
    def select_obs_directory(self):
        directory = QtWidgets.QFileDialog.getExistingDirectory(self, "选择观测文件所在文件夹")
        if directory:
            self.obs_directory = directory
        else:
            self.obs_directory = None

    # File split functionality
    def file_split(self):
        self.select_obs_file()
        if not hasattr(self, 'obs_file') or self.obs_file is None:
            return

        time_dialog = TimeInputDialog(self)
        if time_dialog.exec_() == QtWidgets.QDialog.Accepted:
            start_time_str = time_dialog.get_time()
            duration, ok2 = QtWidgets.QInputDialog.getInt(self, "输入", "请输入持续时间 (秒):", 3600, 1, 86400)
            if not ok2:
                return

            command = run_gfzrnx(os.path.basename(self.obs_file), start_time_str, duration, self.obs_directory)
            self.command_text.setText(command)
            self.execute_command(command)

    # File version conversion functionality
    def file_version_conversion(self):
        self.select_obs_file()
        if not hasattr(self, 'obs_file') or self.obs_file is None:
            return

        version, ok = QtWidgets.QInputDialog.getText(self, "输入", "请输入目标版本（2, 3 或 4）：")
        if not ok or version not in ['2', '3', '4']:
            QtWidgets.QMessageBox.critical(self, "错误", "无效的版本号")
            return

        command = run_version_conversion(os.path.basename(self.obs_file), version, self.obs_directory)
        self.command_text.setText(command)
        self.execute_command(command)

    # File merge functionality
    def file_merge(self):
        self.select_obs_directory()
        if not hasattr(self, 'obs_directory') or self.obs_directory is None:
            return

        o_files = get_o_files(self.obs_directory)
        if not o_files:
            QtWidgets.QMessageBox.information(self, "信息", "没有找到以 o 结尾的文件")
            return

        command = run_file_merge(o_files, self.obs_directory)
        self.command_text.setText(command)
        self.execute_command(command)

    # Satellite exclusion functionality
    def satellite_edit(self):
        self.select_obs_file()
        if not hasattr(self, 'obs_file') or self.obs_file is None:
            return

        prns, ok = QtWidgets.QInputDialog.getText(self, "输入", "请输入PRN列表 (如 G01,G02):")
        if not ok:
            return

        command = run_satellite_edit(os.path.basename(self.obs_file), prns, self.obs_directory)
        self.command_text.setText(command)
        self.execute_command(command)

    # File resampling functionality
    def file_smp(self):
        self.select_obs_file()
        if not hasattr(self, 'obs_file') or self.obs_file is None:
            return

        smp_str, ok = QtWidgets.QInputDialog.getText(self, "输入", "请输入重采样率 (秒):")
        if not ok:
            return

        command = run_file_smp(os.path.basename(self.obs_file), smp_str, self.obs_directory)
        self.command_text.setText(command)
        self.execute_command(command)

    # Ephemeris merge functionality
    def ephemeris_merge(self):
        self.select_obs_directory()
        if not hasattr(self, 'obs_directory') or self.obs_directory is None:
            return

        nav_files = get_nav_files(self.obs_directory)
        if not nav_files:
            QtWidgets.QMessageBox.information(self, "信息", "没有找到以 n 、 g 、c 、l结尾的星历文件")
            return

        command = run_ephemeris_merge(nav_files, self.obs_directory)
        self.command_text.setText(command)
        self.execute_command(command)


    # Helper function to execute the command and handle output
    def execute_command(self, command):
        try:
            result = subprocess.run(command, shell=True, check=True, cwd=self.gfzrnx_directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout_output = result.stdout.decode('utf-8', errors='ignore')
            stderr_output = result.stderr.decode('utf-8', errors='ignore')
            QtWidgets.QMessageBox.information(self, "信息", f"处理完成\nstdout: {stdout_output}\nstderr: {stderr_output}")
        except subprocess.CalledProcessError as e:
            try:
                stderr_output = e.stderr.decode("utf-8")
            except UnicodeDecodeError:
                stderr_output = e.stderr.decode("gbk", errors='ignore')
            QtWidgets.QMessageBox.critical(self, "错误", f"执行命令时出错\nstderr: {stderr_output}")

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ex = GFZRNXTool()
    ex.show()
    sys.exit(app.exec_())
